package com.banmao.desktoptools.screenshotsPDFScene.controller;

import com.banmao.commontools.ScreenshotsPDF;
import com.banmao.desktoptools.FXMain;
import com.banmao.desktoptools.copyfilesScene.FilePojo;
import com.banmao.desktoptools.util.FileIconUtil;
import com.banmao.desktoptools.util.ResultOutput;
import de.felixroske.jfxsupport.FXMLController;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.stage.DirectoryChooser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StopWatch;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;

@Slf4j
@FXMLController
public class ScreenshotsPDFController implements Initializable {

    public Button start_button;
    public TextField cropPage_text;
    public TextArea result_output;
    public TextField cropWidth_text;
    public TextField cropHeight_text;
    public TextField source_path_text;
    public Button source_path_button;
    public TextField export_path_text;
    public Button export_path_button;
    public TreeView file_tree;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        // 监听输入，删除非数字字符
        cropPage_text.textProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                if (!newValue.matches("\\d*")) {
                    cropPage_text.setText(newValue.replaceAll("\\D", ""));
                }
            }
        });
        cropWidth_text.textProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                if (!newValue.matches("\\d*")) {
                    cropWidth_text.setText(newValue.replaceAll("\\D", ""));
                }
            }
        });
        cropHeight_text.textProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                if (!newValue.matches("\\d*")) {
                    cropHeight_text.setText(newValue.replaceAll("\\D", ""));
                }
            }
        });

        // result_output不可编辑
        result_output.setEditable(false);
    }

    public void startCrop(ActionEvent actionEvent) {
        String cropPage = StringUtils.isBlank(cropPage_text.getText()) ? cropPage_text.getPromptText() : cropPage_text.getText();
        String cropWidth = StringUtils.isBlank(cropWidth_text.getText()) ? cropWidth_text.getPromptText() : cropWidth_text.getText();
        String cropHeight = StringUtils.isBlank(cropHeight_text.getText()) ? cropHeight_text.getPromptText() : cropHeight_text.getText();

        final ByteArrayOutputStream bos = new ByteArrayOutputStream();

        String sourcePathText = source_path_text.getText();
        String exportPathText = export_path_text.getText();

        ScreenshotsPDF screenshotsPDF = ScreenshotsPDF.builder()
                .lastCropPage(Integer.parseInt(cropPage))
                .cropWidth(Integer.parseInt(cropWidth))
                .cropHeight(Integer.parseInt(cropHeight))
                .sourcePathText(sourcePathText)
                .exportPathText(exportPathText)
                .outputStream(bos)
                .build();

        result_output.appendText("==============开始执行==============\n");

        CompletableFuture.runAsync(() -> {
            // 异步获取输出流
            ResultOutput resultOutput = new ResultOutput(bos, this.result_output);
            //thread.setDaemon(true);
            resultOutput.start();
            screenshotsPDF.cropPDF();
            resultOutput.stopFlag();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            Platform.runLater(() -> {
                result_output.appendText("==============执行结束==============\n");
            });
            log.info("输出流线程存活状态: {}", resultOutput.isAlive());
        });


        // 折叠文件列表
        file_tree.getRoot().setExpanded(false);

    }

    public void clearResultOutput(ActionEvent actionEvent) {
        // 清空输出信息
        result_output.clear();
    }

    // 获取源路径
    public void getSourcePath(ActionEvent actionEvent) {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择源路径");
        if(StringUtils.isNotBlank(source_path_text.getText())) {
            directoryChooser.setInitialDirectory(new File(source_path_text.getText()));
        }
        File file = directoryChooser.showDialog(FXMain.getStage());
        if(file != null) {
            String sourcePath = file.getAbsolutePath();
            source_path_text.setText(sourcePath);
            if(StringUtils.isBlank(export_path_text.getText())) {
                export_path_text.setText(sourcePath + "_output");
            }

            // 耗时操作，异步进行
            Platform.runLater(() -> {
                StopWatch stopWatch = new StopWatch();
                stopWatch.start("生成文件树");
                // 获取文件树
                FilePojo filePojo = new FilePojo(new File(sourcePath));

                getCurrentFiles(filePojo);

                generateFilesTress(filePojo);

                stopWatch.stop();
                log.info("{} 生成文件树耗费 {} 秒", sourcePath, stopWatch.getTotalTimeSeconds());
            });

        }

    }

    private static final String TEMP_TREEITEM_VALUE = "__TEMP__";

    private void generateFilesTress(FilePojo filePojo) {
        File file = filePojo.getFile();
        TreeItem<Object> root = new TreeItem<>(StringUtils.isBlank(file.getName()) ?
                file.getAbsolutePath() : file.getName());

        root.addEventHandler(TreeItem.branchExpandedEvent(), event -> {
            TreeItem<Object> treeItem = event.getTreeItem();
            //String fileName = (String) treeItem.getValue();
            if(treeItem.getChildren().size() == 0) {
                return;
            }
            TreeItem<Object> firstItem = treeItem.getChildren().get(0);
            if(TEMP_TREEITEM_VALUE.equals(firstItem.getValue())) {
                StopWatch stopWatch = new StopWatch();
                stopWatch.start(file.getAbsolutePath() + "文件树加载");
                treeItem.getChildren().clear();
                // 懒加载
                // 拼接得到绝对路径
                FilePojo treeItemFiles = new FilePojo(new File(file.getAbsolutePath()));
                getCurrentFiles(treeItemFiles);
                generateFilesTress(treeItemFiles, treeItem);
                stopWatch.stop();
                log.info("{} 生成文件树耗费 {} 秒", file.getAbsolutePath(), stopWatch.getTotalTimeSeconds());
            }
        });

        root.addEventHandler(TreeItem.branchCollapsedEvent(), (event) -> {
            TreeItem<Object> item = event.getTreeItem();
            log.info("清理了treeitem {}", item.getValue());
            item.getChildren().clear();
            item.getChildren().add(new TreeItem<>(TEMP_TREEITEM_VALUE));
        });

        WritableImage fileIcon = FileIconUtil.getFileIcon(file.getAbsolutePath());
        root.setGraphic(new ImageView(fileIcon));

        generateFilesTress(filePojo, root);

        file_tree.setRoot(root);
    }

    private void generateFilesTress(FilePojo filePojo, TreeItem<Object> rootItem) {

        for (FilePojo child : filePojo.getChildren()) {
            if (child == null) continue;
            File file = child.getFile();
            TreeItem<Object> item = new TreeItem<>(file.getName());
            String filePath = file.getAbsolutePath();
            if(file.exists() && file.isDirectory()) {
                TreeItem<Object> tempItem = new TreeItem<>(TEMP_TREEITEM_VALUE);
                item.getChildren().add(tempItem);
                item.addEventHandler(TreeItem.branchExpandedEvent(), event -> {
                    TreeItem<Object> treeItem = event.getTreeItem();
                    //String fileName = (String) treeItem.getValue();
                    if(treeItem.getChildren().size() == 0) {
                        return;
                    }
                    TreeItem<Object> firstItem = treeItem.getChildren().get(0);
                    if(TEMP_TREEITEM_VALUE.equals(firstItem.getValue())) {
                        StopWatch stopWatch = new StopWatch();
                        stopWatch.start(filePath + "文件树加载");
                        treeItem.getChildren().clear();
                        // 懒加载
                        // 拼接得到绝对路径
                        FilePojo treeItemFiles = new FilePojo(new File(filePath));
                        getCurrentFiles(treeItemFiles);
                        generateFilesTress(treeItemFiles, treeItem);
                        stopWatch.stop();
                        log.info("{} 生成文件树耗费 {} 秒", filePath, stopWatch.getTotalTimeSeconds());
                    }

                });

            }
            // 设置图标
            WritableImage fileIcon = FileIconUtil.getFileIcon(filePath);
            item.setGraphic(new ImageView(fileIcon));

            rootItem.getChildren().add(item);
        }
    }

    private void getCurrentFiles(FilePojo root) {
        if(root == null) {
            return;
        }

        File file = root.getFile();
        if(file == null || !file.exists()) {
            return;
        }

        if(file.isDirectory()) {
            // 是目录
            ArrayList<FilePojo> children = root.getChildren();
            if(file.listFiles() == null || Objects.requireNonNull(file.listFiles()).length == 0) {
                children.add(null);
                return;
            }
            for (File listfile : Objects.requireNonNull(file.listFiles())) {
                FilePojo filePojo = new FilePojo(listfile);
                children.add(filePojo);
            }

        }

    }

    public void getExportPath(ActionEvent actionEvent) {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择输出路径");
        File file = directoryChooser.showDialog(FXMain.getStage());
        if(file != null) {
            export_path_text.setText(file.getAbsolutePath());
        }
    }
}
